package es.udima.geo.geoserver.rest;

import java.util.Collection;

import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import es.udima.geo.geoserver.business.GpsDataController;
import es.udima.geo.geoserver.business.UserController;
import es.udima.geo.geoserver.entities.GpsData;
import es.udima.geo.geoserver.entities.GpsDataRetrieveResult;
import es.udima.geo.geoserver.entities.GpsDataRetrieveResultError;
import es.udima.geo.geoserver.entities.UserAction;
import es.udima.geo.geoserver.entities.UserActivityLog;
import es.udima.geo.geoserver.entities.UserSessionError;
import es.udima.geo.geoserver.rest.entities.GpsDataRetrieveRequest;
import es.udima.geo.geoserver.rest.entities.GpsDataRetrieveResponse;
import es.udima.geo.geoserver.rest.entities.GpsDataStoreRequest;
import es.udima.geo.geoserver.rest.entities.GpsDataStoreResponse;
import es.udima.geo.geoserver.rest.entities.IResponseError;

/**
 * <p>
 * Servicio de gestión de datos gps para los clientes que utilicen el servicio.
 * </p>
 * 
 * @author david
 * 
 */
@Path("/gps")
public class GpsDataService {

    /**
     * Constructor
     */
    public GpsDataService() {
    }

    /**
     * <p>
     * Recupera los datos GPS almacenados que concuerden con las condiciones del
     * filtro pasado como parámetro dentro de la petición.
     * </p>
     * <p>
     * El filtro debe incluir como mínimo la condición del id de usuario del que
     * se quiere recuperar los datos.
     * </p>
     * <p>
     * Si el filtro no incluye fechas se recuperarán los datos gps del último
     * día que se hayan almacenado datos de ese usuario.
     * </p>
     * <p>
     * Este servicio utiliza una petición segura que debe incluir una sesión de
     * usuario válida.
     * </p>
     * 
     * @param req
     *            Petición de recuperación de datos.
     * @return Resultado de la consulta.
     */
    @POST
    @Path("/user")
    @Produces(MediaType.APPLICATION_JSON)
    @Consumes(MediaType.APPLICATION_JSON)
    public GpsDataRetrieveResponse retrieveUserGpsData(GpsDataRetrieveRequest req) {
	UserController uc = new UserController();
	GpsDataRetrieveResponse res = new GpsDataRetrieveResponse();

	UserActivityLog activity = new UserActivityLog();
	activity.setUserId(req.getUserSession().getUserId());
	activity.setSessionToken(req.getUserSession().getSessionToken());
	activity.setAction(UserAction.RETRIEVE_GPS_DATA);
	String activityId = uc.startUserActivityLog(activity);

	Collection<UserSessionError> sessionErrors = uc.consumeUserSession(req.getUserSession());
	if (!sessionErrors.isEmpty()) {
	    res.addResponseErrors(translateUserSessionErrors(sessionErrors));
	} else {
	    GpsDataController gc = new GpsDataController();
	    GpsDataRetrieveResult gpsRes = gc.retrieveGpsData(req.getFilter());
	    if (gpsRes.isSuccessful()) {
		res.setFilter(gpsRes.getFilter());
		res.setGpsData(gpsRes.getGpsData());
		uc.terminateUserActivityLog(activityId);
	    } else {
		res.addResponseErrors(translateGpsDataRetrieveErrors(gpsRes.getErrors()));
	    }
	}

	return res;
    }

    /**
     * <p>
     * Graba en base de datos la lista de datos gps pasada como parámetro.
     * </p>
     * <p>
     * Este servicio utiliza una petición segura que debe incluir una sesión de
     * usuario válida.
     * </p>
     * 
     * @param req
     *            Petición de grabación de datos.
     * @return Resultado de la grabación.
     */
    @POST
    @Path("/store")
    @Produces(MediaType.APPLICATION_JSON)
    @Consumes(MediaType.APPLICATION_JSON)
    public GpsDataStoreResponse storeUserGpsData(GpsDataStoreRequest req) {
	UserController uc = new UserController();
	GpsDataStoreResponse res = new GpsDataStoreResponse();

	UserActivityLog activity = new UserActivityLog();
	activity.setUserId(req.getUserSession().getUserId());
	activity.setSessionToken(req.getUserSession().getSessionToken());
	activity.setAction(UserAction.STORE_GPS_DATA);
	String activityId = uc.startUserActivityLog(activity);

	Collection<UserSessionError> sessionErrors = uc.consumeUserSession(req.getUserSession());
	if (!sessionErrors.isEmpty()) {
	    res.addResponseErrors(translateUserSessionErrors(sessionErrors));
	} else {
	    String uid = req.getUserSession().getUserId();
	    for (GpsData gd : req.getGpsData()) {
		gd.setUserId(uid);
	    }
	    GpsDataController gc = new GpsDataController();
	    gc.storeGpsData(req.getGpsData());
	    uc.terminateUserActivityLog(activityId);
	}

	return res;
    }

    /*-----------------------------------------------------------------------------------------------*/

    /**
     * <p>
     * Método auxiliar para traducir los errores de sesión.
     * </p>
     * 
     * @param errors
     *            Colección de errores de sesión.
     * @return Colección de errores traducida.
     */
    private Collection<IResponseError> translateUserSessionErrors(Collection<UserSessionError> errors) {
	return new RestServiceErrorHelper().translateUserSessionErrors(errors);
    }

    /**
     * <p>
     * Método auxiliar para traducir los errores de recuperación de datos gps.
     * </p>
     * 
     * @param errors
     *            Colección de errores de recuperación de datos gps.
     * @return Colección de errores traducida.
     */
    private Collection<IResponseError> translateGpsDataRetrieveErrors(Collection<GpsDataRetrieveResultError> errors) {
	return new RestServiceErrorHelper().translateGpsDataRetrieveErrors(errors);
    }
}
